package messengerserver;

import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import messengercommon.common.ClientRMI;
import messengercommon.common.ServerRMI;
import messengercommon.dto.Message;
import messengercommon.person.Contact;
import messengercommon.person.EnumStatus;
import messengercommon.person.Person;
import messengerserver.DBExch.PText;

/**
 *
 * @author Samus
 */
public class Server extends UnicastRemoteObject implements ServerRMI {

    private Map<String, ClientRMI> usersOnline;

    public Server() throws RemoteException {
        super();
        this.usersOnline = new HashMap<String, ClientRMI>();
    }

    @Override
    public void addObserver(ClientRMI observer, String nomb) throws RemoteException {
        this.usersOnline.put(nomb, observer);
        System.out.println("New Observer " + nomb);
    }

    @Override
    public int autentifyMessage(Message message) throws RemoteException {
        int res = 0;
        try {
            if (this.usersOnline.containsKey(message.getDestino())) {
                ClientRMI client = usersOnline.get(message.getDestino());
                System.out.println("Received message from: " + message.getOrigen() + " to " + message.getDestino());
                client.receiveMessage(message);
                PText.getInstance().persistirMensaje(message);
                res = 1;
            } else {
                res = 2;
            }
        } catch (Exception ex) {
            return res;
        }
        return res;
    }

    @Override
    public int autentifyUser(Person pers, ClientRMI client) throws RemoteException {
        int res = 0;
        if (!usersOnline.containsKey(pers.getUsername())) {
            try {
                res = UserAdmin.getInstance().autentifyUser(pers);
            } catch (Exception ex) {
                Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
            }
            addObserver(client, pers.getUsername());
        } else {
            res = 3;
        }
        return res;
    }

    @Override
    public void userDisconnect(Person pers) throws RemoteException {
        pers.setStatus(EnumStatus.DISCONNECTED);
        this.usersOnline.remove(pers.getUsername());
        readConList(pers);
        System.out.println(pers.getUsername() + " disconnected.");
    }

    @Override
    public Person userData(String nomb) throws RemoteException {
        Person pers = null;
        try {
            pers = UserAdmin.getInstance().readUser(nomb);
        } catch (Exception ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
        return pers;
    }

    @Override
    public boolean newUser(Person pers) throws RemoteException {
        boolean res = false;
        try {
            res = UserAdmin.getInstance().persistUser(pers);
            System.out.println("New user input.");
        } catch (Exception ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
        return res;
    }

    @Override
    public int addContact(Person person, String nomb) throws RemoteException {
        int res = 0;
        try {
            res = UserAdmin.getInstance().autentifyContact(nomb);
            if (res == 2) {
                Contact contact = UserAdmin.getInstance().readContact(nomb);
                person.getContacts().add(contact);
                UserAdmin.getInstance().persistUser(person);
                readConList(person);
            }
        } catch (Exception ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
        return res;
    }

    @Override
    public void userDataChanged(Person person) throws RemoteException {
        try {
            UserAdmin.getInstance().persistUser(person);
            readConList(person);
        } catch (Exception ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public List<Contact> readContListFromDB(String nomb) throws Exception {
        List<Contact> contactlist = UserAdmin.getInstance().readUser(nomb).getContacts();
        return contactlist;
    }

    //Método para pasar las listas de contactos actualizadas a cada usuario en el HashMap (Conectados)
    @Override
    public void readConList(Person pers) throws RemoteException {
        for (Contact c : pers.getContacts()) {
            try {
                if (this.usersOnline.containsKey(c.getUsername())) {
                    List<Contact> list = actualizedList(c.getUsername());
                    this.usersOnline.get(c.getUsername()).contactList(list);
                }
                List<Contact> list = new ArrayList<Contact>();
                list = actualizedList(pers.getUsername());
                if (this.usersOnline.containsKey(pers.getUsername())) {
                    this.usersOnline.get(pers.getUsername()).contactList(list);
                }
            } catch (Exception ex) {
                System.out.println("Error al pasar la lista de contactos");
            }
        }
    }

    public List<Contact> actualizedList(String nomb) throws Exception {
        List<Contact> newList = readContListFromDB(nomb);
        for (Contact c : newList) {
            c = asignarEstado(c);
        }
        return newList;
    }

    public Contact asignarEstado(Contact c) {
        Contact con = c;
        if (this.usersOnline.containsKey(con.getUsername())) {
            if (c.getStatus() == null) {
                con.setStatus(EnumStatus.AVAILABLE);
            }
        } else {
            con.setStatus(EnumStatus.DISCONNECTED);
        }
        return con;
    }

    @Override
    public ArrayList<String> readLog()  throws RemoteException{
        ArrayList<String> log = new ArrayList<String>();
        try {
            log = PText.getInstance().leerLog();
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
        return log;
    }
}
